(*OOPTest             Johannes Karder, 2011-11-10*)
(*Test program for the hydrac pseudocode compiler*)

PROGRAM OOPTest;

  TYPE 
    Base = OBJECT
      PRIVATE a: REAL;
      PUBLIC b: REAL;

      (*constructors must have same name as the*)
      (*containing class. hydrac compiles the*)
      (*name to "Init" (needed for pascal only)*)
      PUBLIC CONSTRUCTOR Init(a: REAL; b: REAL); VIRTUAL; 
      PUBLIC FUNCTION GetA: REAL; VIRTUAL; 
      PUBLIC PROCEDURE PrintB; VIRTUAL; 
    END;

    Derived = OBJECT(Base)
      PUBLIC CONSTRUCTOR Init(a: REAL; b: REAL); VIRTUAL; 
      PRIVATE FUNCTION GetB: REAL; VIRTUAL; 
      PUBLIC PROCEDURE PrintB; VIRTUAL; 
      PUBLIC FUNCTION Pow(a: REAL; b: REAL): REAL; VIRTUAL; 
      PUBLIC FUNCTION Root(a: REAL; b: REAL): REAL; VIRTUAL; 
    END;

  (*constructor*)
  CONSTRUCTOR Base.Init(a: REAL; b: REAL);
  BEGIN 
    SELF.a := a;
    SELF.b := b;
  END;

  FUNCTION Base.GetA: REAL;
  BEGIN 
    GetA := SELF.a;
  END;

  PROCEDURE Base.PrintB;
  BEGIN 
    WriteLn('Base.PrintB: ', SELF.b);
  END;

  (*constructor*)
  CONSTRUCTOR Derived.Init(a: REAL; b: REAL);
  BEGIN 
    INHERITED Init(a, b);
  END;

  FUNCTION Derived.GetB: REAL;
  BEGIN 
    GetB := SELF.b;
  END;

  PROCEDURE Derived.PrintB;
  BEGIN 
    WriteLn('Derived.PrintB: ', SELF.b);
  END;

  FUNCTION Derived.Pow(a: REAL; b: REAL): REAL;
    VAR 
      res: REAL;
  BEGIN 
    res := a;
    WHILE (b > 1) DO BEGIN 
      res := res * a;
      b := b - 1;
    END;
    Pow := res;
  END;

  FUNCTION Derived.Root(a: REAL; b: REAL): REAL;
    VAR 
      i: INTEGER;
      res: REAL;
  BEGIN 
    res := a / 2;
    FOR i := 1 TO 1000 DO BEGIN 
      res := ((b - 1) * SELF.Pow(res, b) + a) / (b * SELF.Pow(res, b - 1));
    END;
    Root := res;
  END;

  VAR 
    m1: ^Derived;
    m2: ^Derived;
    m3: ^Base;

BEGIN 
  New(m1);
  WriteLn('2^16 = ', m1^.Pow(2, 16));
  New(m2, Init(3, 4));
  WriteLn('16th root of 65536 = ', 
  m2^.Root(65536, 16));
  Dispose(m1);
  New(m3, Init(5, 6));
  m3^.PrintB();  (*calls Base.PrintB()*)
  Dispose(m3);
  m3 := m2;
  m3^.PrintB();  (*calls Derived.PrintB()*)
  Dispose(m2);
END.